// Use Parse.Cloud.define to define as many cloud functions as you want.
// For example:
Date.prototype.addHours= function(h){
    this.setHours(this.getHours()+h);
    return this;
}
Date.prototype.addMinutes= function(h){
    this.setMinutes(this.getMinutes()+h);
    return this;
}

function sendFeedbackPush(fromId, toId, toOrg, toName, routeId, pushTime)
{
    //doesn't work, dunno why =P too lazy to debug at this moment
    console.log("entered push function");
    console.log(pushTime);
    console.log(toId);
    console.log(toName);
    console.log(toOrg);
    console.log(fromId);

    var moment = require("cloud/moment.js");
    //feedback FROM a user that is being given TO another user
    Parse.Push.send({
        channels: ["user_" + fromId],
        data: {
            action: "com.demo.savareedemo.FeedbackActivity",
            alert: "How did it go? Help us improve! : )",
            name: toName,
            org: toOrg,
            userId: toId,
        },
        push_time: pushTime
    }, {
        success: function () {
            // Push was successful
            alert: "successfully scheduled push"
            console.log("push successfullo");
        },
        error: function (error) {
            // Handle error
            alert: "error scheduling push"
            console.log(error);
        }
    });
    return true;
}

Parse.Cloud.define("requestRide", function(request, response) {
	// adds a tracking entry in the routeTrack table every time a passenger
	// tries to contact a driver. reports passengerId, routeId and driverId
	// also schedules a push to be sent to users every time a route is booked.
	var moment = require('cloud/moment.js');
    var passengerName = request.params.name;
	var timeZone = 5;
	var passengerId = Parse.User.current().id;
	var routeId = request.params.route;
	var driverId, travelTime, driverName;
	var query = new Parse.Query("route");
	var pushTime;
	query.equalTo("objectId", routeId);
	query.find({
		success: function(results) {
			alert("Successfully retrieved " + results.length + " routes.");
			driverId = results[0].get("user_id");			
			var trackClass = Parse.Object.extend("routeTrack");
			var trackRequest = new trackClass();
			console.log(driverId + "driverId");
			console.log(passengerId + "passengerId");
			console.log(routeId + "routeId");
		    // currently all dates stored are stored in PST as travelTime in the database
		    // system assuming the GMT+5 are actually UTC. Need to add -5 to hours to get to
		    // UTC

			travelTime = results[0].get("travelTime");
			var timeMoment = new moment(travelTime);
			console.log(timeMoment.toString());
			console.log(travelTime.toString());
			timeMoment.subtract('hours', 5); //subtract 5 hours to make it in UTC
			tempMoment = new moment();
			tempMoment.hours(timeMoment.hours());
			tempMoment.minutes(timeMoment.minutes());
			timeMoment = new moment();
			tempMoment.add('hours', 1);
			if (tempMoment.isBefore(timeMoment))
			{
				tempMoment.add('days',1);
			}
			pushTime = tempMoment.toDate();
			console.log("pushtime:");
			console.log(pushTime);
			
			trackRequest.set("passenger", passengerId);
			trackRequest.set("driver", driverId);
			trackRequest.set("route", routeId);
			
			trackRequest.save(null,{
				success:function(person) {
					//create, schedule and send the feedback push query request
				    console.log("tracking");
				    //send to driver	
				    console.log(request.params.fromName+"fromName");
				    console.log(request.params.fromOrg + "fromOrg");
				    Parse.Push.send({
						//						where: pushQuery,
						channels: ["user_"+driverId],
						data: {
							action: "com.demo.savareedemo.FeedbackActivity",
							alert: "How did it go? Help us improve! : )",
							name: request.params.fromName,
							org: request.params.fromOrg,
							userId: passengerId,
						},
						push_time: pushTime
						}, {
						success: function() {
							// Push was successful
							alert: "successfully scheduled push1"
						},
						error: function(error) {
							// Handle error
							alert: "error scheduling push1"
						}
					});
					//send to passenger
				    console.log(results[0].get("username")+"username");
				    console.log(results[0].get("org")+"org");
				    Parse.Push.send({
						//						where: pushQuery,
						channels: ["user_"+passengerId],
						data: {
							action: "com.demo.savareedemo.FeedbackActivity",
							alert: "How did it go? Help us improve! :)",
							name: results[0].get("username"),
							org: results[0].get("org"),
							userId: driverId,
						},
						push_time: pushTime
						}, {
						success: function() {
							// Push was successful
							alert: "successfully scheduled push2"
						},
						error: function(error) {
							// Handle error
							alert: "error scheduling push2"
						}
					});
					// end pushQuery					
					response.success("success");
				},
				error:function(error) {
				    response.error("Error1: " + error.code + " " + error.message);
				    console.log("nottracking");
				}
			});
		},
		error: function(error) {
			response.error("Error2: " + error.code + " " + error.message);
		}
	});

	//var query = new Parse.Query("User");
	//query.equalTo("objectId", driverId);
	//var query1 = new Parse.Query("User");
	//query1.equalTo("objectId", passengerId);
	//var mainQuery = Parse.Query.or(query, query1);
	//console.log("here");
	//mainQuery.find({
	//    success: function (results) {
	//        // results contains a list of players that either have won a lot of games or won only a few games.
	//        console.log("successfullo");
	//        console.log(results);
	//        if (results.length > 1) {
	//            console.log("name1");
	//            var name = results[1].get('fname') + " " + results[1].get('lname');
	//            console.log(name);
	//            sendFeedbackPush(results[0].get('objectID'), results[1].get('objectId'), results[1].get('org'), name, routeId, pushTime);
	//            console.log("name2");
	//            var name = results[0].get('fname') + " " + results[0].get('lname');
	//            console.log(name);
	//            sendFeedbackPush(results[1].get('objectID'), results[0].get('objectId'), results[0].get('org'), name, routeId, pushTime);
	//        }
	//        else {
	//            console.log("name");
	//            var name = results[0].get('fname') + " " + results[0].get('lname');
	//            console.log(name);
	//            sendFeedbackPush(results[0].get('objectID'), results[0].get('objectId'), name, routeId, pushTime);
	//            sendFeedbackPush(results[0].get('objectID'), results[0].get('objectId'), name, routeId, pushTime);
	//        }
	//    },
	//    error: function (error) {
	//        console.log("error");
	//        // There was an error.
	//    }
	//});

});

Parse.Cloud.define("requestRate", function(request, response) {
	// adds a tracking entry in the routeTrack table every time a passenger
	// tries to contact a driver. reports passengerId, routeId and driverId
	//TODO: should also add to a driver's total distance driven (from where
	//fuel + CO2 + $$$ saved can be calculated)
    var rater = request.params.rater;
	var ratee = request.params.ratee;
	var rating = request.params.rating;
	var comments = request.params.comments;

	var ratingClass = Parse.Object.extend("ratings");
	var rateRequest = new ratingClass();
			
	rateRequest.set("rater", rater);
	rateRequest.set("ratee", ratee);
	rateRequest.set("rating", rating);
	rateRequest.set("comments", comments);
	rateRequest.save(null,{
		success:function(person) { 
			response.success("success");
		},
		error:function(error) {
			response.error("Error1: " + error.code + " " + error.message);
		}
	});
	var userObject = Parse.Object.extend("User");
	var query = new Parse.Query(userObject);
	query.equalTo("objectId", ratee);
	console.log("here1");
	query.first({
	    success: function (result) {
//            console.log("RESULT: " + result)
		    //var rating = result.get("rating");
		    var rating1 = result.get("rating");
//		    console.log(rating1+ " rating");
		    var numRatings = result.get("numRatings");
//		    console.log(numRatings + " numRating");
			if(rating1 == null) rating1 = 0.0;
			if(numRatings == null) numRatings = 0;
			var ratingPoints = rating1 * numRatings + rating;
			console.log(ratingPoints + " ratingPoints");
			numRatings = numRatings + 1;
			rating1 = ratingPoints / numRatings;
			console.log(rating1 + " newRating");
			result.set("ratingPoints", ratingPoints);
			result.set("rating", rating1);
			result.set("numRatings", numRatings);
			result.save();
		},
		error: function(error) {
			alert("Error: " + error.code + " " + error.message);
		}
	});
});

Parse.Cloud.define("requestTrack", function(request, response) {
	// adds a tracking entry in the routeTrack table every time a passenger
	// tries to contact a driver. reports passengerId, routeId and driverId
    var passengerId = Parse.User.current().id;
	var routeId = request.params.route;
	var driverId;
	var query = new Parse.Query("route");
	query.equalTo("objectId", routeId);
	query.find({
		success: function(results) {
			alert("Successfully retrieved " + results.length + " routes.");
			driverId = results[0].get("user_id");			
			var trackClass = Parse.Object.extend("routeTrack");
			var trackRequest = new trackClass();
			
			trackRequest.set("passenger", passengerId);
			trackRequest.set("driver", driverId);
			trackRequest.set("route", routeId);
			
			trackRequest.save(null,{
				success:function(person) { 
					response.success("success");
				},
				error:function(error) {
					response.error("Error1: " + error.code + " " + error.message);
				}
			});									
			
			//check if this route has been booked before.
/*			var query = new Parse.Query("routeTrack");
			query.equalTo("passenger", passengerId);
			query.equalTo("driver", driverId);
			query.equalTo("route", routeId);
			query.find({ //if a track request exists for that route, do not update.
				success:function(results){
					if(results.length==0 || results == null){

						var trackClass = Parse.Object.extend("routeTrack");
						var trackRequest = new trackClass();
						
						trackRequest.set("passenger", passengerId);
						trackRequest.set("driver", driverId);
						trackRequest.set("route", routeId);
						
						trackRequest.save(null,{
							success:function(person) { 
								response.success("success");
							},
							error:function(error) {
								response.error("Error1: " + error.code + " " + error.message);
							}
						});									
					}
				},
				error:function(error){
					response.error("Error3: " + error.code + " " + error.message);
				}
			});
*/		},
		error: function(error) {
			response.error("Error2: " + error.code + " " + error.message);
		}
	});
});

function deg2rad(degrees){
    radians = degrees * (Math.PI/180);
    return radians;
}
 
function Haversine(lat1,lon1,lat2,lon2) {
    deltaLat = lat2 - lat1 ;
    deltaLon = lon2 - lon1 ;
    earthRadius = 6371; // in meters 3959 in miles.
    alpha    = deltaLat/2;
    beta     = deltaLon/2;
    a        = Math.sin(deg2rad(alpha)) * Math.sin(deg2rad(alpha)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(deg2rad(beta)) * Math.sin(deg2rad(beta)) ;
    c        = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    distance =  earthRadius * c;
    return distance.toFixed(2);
}
 
Parse.Cloud.define("nearestRoutes", function(request, response) {
	// takes as input the start and end point's latitudes and longitudes, gender, genderFilter,
	// organization and privacy settings of searcher, and the date of search. gets those routes that
	// are filtered by organization and privacy settings. Then decides if this route is on the day of
	// interest or recurs on the day of interest. Then checks each route at 10 points along the route
	// to determine closest pickup and dropoff.  Then returns those routes where the total walk < 10

    var moment = require('cloud/moment.js');
    var startlongitude = request.params.startlongitude;
    var startlatitude = request.params.startlatitude;
    var stoplongitude = request.params.stoplongitude;
    var stoplatitude = request.params.stoplatitude;
    var privacy = request.params.privacy;
    var query = new Parse.Query("route");
    var genderFilter, date, recurDays, org;
         
    try {
        genderFilter = request.params.genderFilter;
    } catch(err){}
    try {
        date = request.params.date;
    } catch(err){}
    try {
        org = request.params.org;
    } catch(err){}
 
 
//#########################WORKING#########################################//
//  /*
    if(privacy == 1){   //if privacy is 1, then search among routes only.
        query.equalTo("org", org);
    }
    else{
        query.equalTo("privacy", 0)
        var query1 = new Parse.Query("route");
        query1.equalTo("org", org);
        query = Parse.Query.or(query, query1);
    }
//  */
//#########################################################################//
    /*  THIS BIT IS NOT WORKING. WILL HAVE TO MAKE COMPOUND QUERY USING TRUTH TABLE OR SOME OTHER MEANS
    if(genderFilter == 1){  //if privacy is 1, then search among routes only.
        query.equalTo("gender", request.params.gender);
    }
    else{
        query.equalTo("genderFilter", 0);
        var query1 = new Parse.Query("route");
        query1.equalTo("gender", request.params.gender);
        query = Parse.Query.or(query, query1);
    }
//   */
//#########################################################################//
    //here we need to return only routes posted for after today.
	query.limit(1000);
    query.find({
        success: function(results) {
        var retVals = new Array();
        var sum = 0;
        var minDistStart, minDistStop, tempDistStart, tempDistStop, startIndex=0, stopIndex=10;
        var tempLat, tempLong, totalWalk;
        var latlngString, recurDays;
        var dateMoment = new moment(date, "MM-DD-YYYY");
 
         
//############ MAIN FOR LOOP TO ITERATE OVER ALL POSTED ROUTES #########################
        for (var i = 0; i < results.length; ++i) {
//######################################################################################
        //to check for genderFilter
        if(genderFilter!=null)
        {
            if(genderFilter==1){
                if(results[i].get("gender") != request.params.gender) continue;
            }
            else {
                if(!( (results[i].get("gender") == request.params.gender) || (results[i].get("genderFilter") == genderFilter) )) continue;
            }
        }
        //check if this route is after the current date.
        try{        
            var tempDateMoment = new moment(results[i].get("date").toString(),"MM-DD-YYYY");
        } catch (err) {  }
        //check if this is a recurring route that occurs on the search date
        var recurs=false;
        try{ recurDays = results[i].get("repeatDay"); 
                while(recurDays.length > 0){
                if(recurDays[0] == dateMoment.day()+1)
                    recurs = true;
                recurDays = recurDays.substring(2,recurDays.length); //TODO
            }
        } catch (err) { }
             
        // TODO need to make sure this is only for date entered during search           
        //  if(dateMoment.isSame(tempDateMoment) || dateMoment.isBefore(tempDateMoment) || recurs)  {}
        if(dateMoment.isSame(tempDateMoment) || recurs) {
 
            //calculate distances for each of the eleven points and the start and end points
            latlngString = results[i].get("endPoint");
            tempLat = parseFloat(latlngString.substring(latlngString.indexOf("(")+1,latlngString.indexOf(",")));
            tempLong = parseFloat(latlngString.substring(latlngString.indexOf(",")+1, latlngString.indexOf(")")));
     
            minDistStart = Haversine(startlatitude,startlongitude,tempLat,tempLong);
            minDistStop = Haversine(stoplatitude,stoplongitude,tempLat,tempLong);
			
            for(var j=0; j<10; j++){
                try{
                    latlngString = results[i].get("point"+j);
                    tempLat = parseFloat(latlngString.substring(latlngString.indexOf("(")+1,latlngString.indexOf(",")));
                    tempLong = parseFloat(latlngString.substring(latlngString.indexOf(",")+1, latlngString.indexOf(")")));
                    tempDistStart = Haversine(startlatitude, startlongitude, tempLat, tempLong);
                    tempDistStop = Haversine(stoplatitude, stoplongitude, tempLat, tempLong);
     
                    if(tempDistStart<minDistStart){
                        minDistStart = tempDistStart; 
                        startIndex = j;
                    }   
                    if(tempDistStop<minDistStop){
                        minDistStop = tempDistStop; 
                        stopIndex = j;
                    }   
                }catch(err){}
            }
            //now minDistStart is the closest distance from the current startPoint and minDistStop
            //is the closest distance from the current stopPoint.
            totalWalk = parseFloat(minDistStart)+parseFloat(minDistStop);
            if((totalWalk<10) && (stopIndex>startIndex)){
//            if((totalWalk<10)){
				results[i].push("pickup", startIndex);
				results[i].dropoff = stopIndex;
				retVals.push(results[i]);               
            }
        }
    }
        response.success(retVals);
    },
    error: function() { response.error("route lookup failed"); }
  });
});